<?php
/**
 * Function:
 * Description:
 * Abo 2019/4/21 23:53
 * Email: abo2013@foxmail.com
 */

namespace App\Logic;


class SmartSyncDataLogic
{
    protected $tableName, $updateBatch;

    public function __construct( string $tableName = '', string $updateBatch = '' )
    {
        if ( !$tableName || !$updateBatch ) {
            throw new \Exception( '未设置表名' );
        }

        $this->tableName = $tableName;
        $this->updateBatch = $updateBatch;
    }

    /**
     * 功能字段
     * md5_new 更新数组生成 新MD5 32
     * md5_origin 原MD5 32
     * update_batch 更新批次
     * remove_at 移除时间
     *
     * 流程:
     * 1 生成更新批次标识 update_batch
     * 2 忠诚同步数据
     * 3 把 新增 同步数据 更新到 我方逻辑表 (remove_time = 0 && update_batch = 当前更新标识 && md5_origin = '' && md5_new != '')
     * 4 把 变更 同步数据 按条件更新到 我方逻辑表 (remove_time = 0 && update_batch = 当前更新标识 && md5_origin != '' && md5_new != md5_origin)
     * 5 把 失联 同步数据 按条件更新到 我方逻辑表 (remove_time = 0 && update_batch != 当前更新标识 && md5_origin != '' && md5_new = '')
     * 6 本更新批次,收尾标记
     * 6.1 变动的 md5_origin = md5_new
     * 6.2 失联的 remove_time = time()
     * 6.3 全部 md5_new = ''
     *
     * @param array $syncData
     * @return bool
     * @throws \Exception
     */
    public function syncDataIntoTable( array $syncData = [] )
    {
        $this->insertSyncData2DB(); // 第一步:忠诚同步数据到数据库

        $this->updateMd5Origin(); // 本更新批次,收尾标记
    }

    /** 第一步:忠诚同步数据到数据库 */
    protected function insertSyncData2DB()
    {
        if ( !$syncData ) { return false;  }

        $chunkArr = array_chunk($syncData, 500);
        foreach ($chunkArr as $v2Arr) {
            foreach ( $v2Arr as $v2Insert ) {
                $temData2Insert = $v2Insert;
                $temData2Insert [ 'update_batch' ] = $this->updateBatch;
                // $temData2Insert [ 'md5_origin' ] = '';
                $temData2Insert [ 'md5_new' ] = md5( implode('_', $data2Insert ) );
                $temData2Insert [ 'remove_time' ] = 0;

                $this->duplicateKeyInsert( $temData2Insert, $this->tableName );
            }
        }
    }

    /** 第二步:按逻辑 更新 变更数据 到 业务表 @throws \Exception*/
    public function syncData2ProductLogic()
    {
        // todo 重写业务代码
    }


    /**
     * 本更新批次,收尾标记
     * 6 本更新批次,收尾标记
     * 6.1 变动的 md5_origin = md5_new
     * 6.2 失联的 remove_time = time()
     * 6.3 全部 md5_new = ''
     */
    protected function updateMd5Origin()
    {
        // 新增,变更的复位
        $sql2Str = "UPDATE {$this->tableName} SET md5_origin = md5_new WHERE md5_new <> '' AND update_batch = '{$this->updateBatch}'";
        return \DB::update( $sql2Str );
        // 失联
        $sql2Str = "UPDATE {$this->tableName} SET remove_time = ".time()." WHERE md5_new != md5_origin AND md5_new = '' AND update_batch = '{$this->updateBatch}'";

        $sql2Str = "UPDATE {$this->tableName} SET md5_new = ''";
    }

    /** 单个插入更新 @throws \Exception */
    protected function duplicateKeyInsert( array $fileCategoryRelationArr, string $tableName = '' )
    {
        if ( !$fileCategoryRelationArr || !$tableName ) { return false; }

        $insertColumns = null;
        $updateColumnsKeyArr = $updateColumnsKeyStr = false;

        // 添加部分绑定
        $insertColumns = array_keys( $fileCategoryRelationArr );
        $insertColumnsBindValue = array_values( $fileCategoryRelationArr );

        $insertColumnsQuestionStr = implode( ',', array_fill( 0, count( $fileCategoryRelationArr ), '?' ) );
        $insertColumnsKeyStr = implode( ',', $insertColumns );

        // 更新部分数据绑定
        foreach ( $fileCategoryRelationArr as $k2cate => $v2cate ) {
            $updateColumnsKeyArr[] = "{$k2cate}='".addslashes($v2cate)."'";
        }

        $updateColumnsKeyStr = implode( ',', $updateColumnsKeyArr );

        $duplicateInsertSql = "insert into {$tableName} ( {$insertColumnsKeyStr} ) "
            . "values ( {$insertColumnsQuestionStr} )  ON DUPLICATE KEY UPDATE {$updateColumnsKeyStr}";
        $ret2Return = \DB::insert( $duplicateInsertSql, $insertColumnsBindValue );

        return $ret2Return;
    }

    /** 生成 更新批次 */
    protected function createUpdateBatch()
    {
        return date( 'mdHi' ) . substr( md5( time() ), 0, 3 );
    }
}